package com.ruoyi.common.core.utils;

import cn.hutool.core.collection.CollUtil;
import org.apache.commons.lang3.StringUtils;

import java.util.*;
import java.util.function.*;
import java.util.stream.Collector;
import java.util.stream.Collectors;
import java.util.stream.Stream;

/**
 * @author liyang
 * @date 2022/2/24 10:55
 */
public class CommonStreamUtil {

    /**
     * 排序
     *
     * @param list       list
     * @param comparator comparator
     * @param <T>        T
     * @return T 列表
     */
    public static <T> List<T> sorted(Collection<T> list, Comparator<T> comparator) {
        return list.stream().sorted(comparator).collect(Collectors.toList());
    }

    /**
     * 重新指定排序
     *
     * @param list  list
     * @param ids   ids
     * @param getId getId
     * @param <T>   T
     * @param <V>   V
     * @return T 列表
     */
    public static <T, V> List<T> sortByIds(Collection<T> list, Collection<V> ids, Function<T, V> getId) {
        Map<V, T> map = CommonStreamUtil.toOrderlyMap(list, getId);
        return CommonStreamUtil.transList(ids, map::containsKey, map::get);
    }

    /**
     * 列表拼接成String
     *
     * @param list      list
     * @param getS      getS
     * @param delimiter delimiter
     * @param <T>       T
     * @return String
     */
    public static <T> String join(Collection<T> list, Function<T, String> getS, String delimiter) {
        return list.stream().map(getS).collect(Collectors.joining(delimiter));
    }

    /**
     * 列表拼接成String
     *
     * @param list       list
     * @param getS       getS
     * @param isNotBlank isNotBlank
     * @param delimiter  delimiter
     * @param <T>        T
     * @return String
     */
    public static <T> String join(Collection<T> list, Function<T, String> getS, boolean isNotBlank, String delimiter, String defaultBlank) {
        Stream<String> stringStream = list.stream().map(getS);
        if (isNotBlank) {
            stringStream = stringStream.filter(StringUtils::isNotBlank);
        }
        String result = stringStream.collect(Collectors.joining(delimiter));
        return StringUtils.defaultIfBlank(result, defaultBlank);
    }

    /**
     * 获取第一个元素
     *
     * @param list   list
     * @param filter filter
     * @param def    def
     * @param <T>    T
     * @return T
     */
    public static <T> T getFirst(Collection<T> list, Predicate<T> filter, T def) {
        return list.stream().filter(filter).findFirst().orElse(def);
    }

    /**
     * 获取第一个元素
     *
     * @param list list
     * @param <T>  T
     * @return T
     */
    public static <T> T isExistFirst(Collection<T> list) {
        return list.stream().findFirst().orElseThrow(RuntimeException::new);
    }

    /**
     * 获取第一个元素
     *
     * @param list   list
     * @param filter filter
     * @param <T>    T
     * @return T
     */
    public static <T> T isExistFirst(Collection<T> list, Predicate<T> filter) {
        return list.stream().filter(filter).findFirst().orElseThrow(RuntimeException::new);
    }

    /**
     * 获取第一个元素
     *
     * @param list              list
     * @param filter            filter
     * @param exceptionSupplier exceptionSupplier
     * @param <T>               T
     * @return T
     */
    public static <T, X extends Throwable> T isExistFirst(Collection<T> list, Predicate<T> filter, Supplier<? extends X> exceptionSupplier) throws Throwable {
        return list.stream().filter(filter).findFirst().orElseThrow(exceptionSupplier);
    }

    /**
     * 获取第一个元素
     *
     * @param list list
     * @param <T>  T
     * @return Optional
     */
    public static <T> Optional<T> findFirst(Collection<T> list) {
        return list.stream().findFirst();
    }

    /**
     * 获取第一个元素
     *
     * @param list   list
     * @param filter filter
     * @param <T>    T
     * @return Optional
     */
    public static <T> Optional<T> findFirst(Collection<T> list, Predicate<T> filter) {
        return list.stream().filter(filter).findFirst();
    }

    /**
     * 转换list
     *
     * @param list  list
     * @param trans trans
     * @param <T>   T
     * @param <V>   V
     * @return List
     */
    public static <T, V> List<V> transList(Collection<T> list, Function<T, V> trans) {
        return list.stream().map(trans).collect(Collectors.toList());
    }

    /**
     * 转换list并且按照指定顺序
     *
     * @param list  list
     * @param trans trans
     * @param <T>   T
     * @param <V>   V
     * @return List
     */
    public static <T, V, A> List<V> transListAndSort(Collection<T> list, Function<T, V> trans, Collection<A> ids, Function<T, A> getId) {
        Map<A, T> map = CommonStreamUtil.toOrderlyMap(list, getId);
        return ids.stream().filter(map::containsKey).map(e -> trans.apply(map.get(e))).collect(Collectors.toList());
    }

    /**
     * 转换list
     *
     * @param list   list
     * @param trans  trans
     * @param filter 过滤
     * @param <T>    T
     * @param <V>    V
     * @return List
     */
    public static <T, V> List<V> transList(Collection<T> list, Predicate<T> filter, Function<T, V> trans) {
        return list.stream().filter(filter).map(trans).collect(Collectors.toList());
    }

    /**
     * 转换list
     *
     * @param list   list
     * @param trans  trans
     * @param filter 过滤
     * @param <T>    T
     * @param <V>    V
     * @return List
     */
    public static <T, V> List<V> transList(Collection<T> list, Function<T, V> trans, Predicate<V> filter) {
        return list.stream().map(trans).filter(filter).collect(Collectors.toList());
    }

    /**
     * 转换set
     *
     * @param list  list
     * @param trans trans
     * @param <T>   T
     * @param <V>   V
     * @return List
     */
    public static <T, V> Set<V> transSet(Collection<T> list, Function<T, V> trans) {
        return list.stream().map(trans).collect(Collectors.toSet());
    }

    /**
     * 转换set
     *
     * @param list  list
     * @param trans trans
     * @param <T>   T
     * @param <V>   V
     * @return List
     */
    public static <T, V> Set<V> transSet(Collection<T> list, Predicate<T> filter, Function<T, V> trans) {
        return list.stream().filter(filter).map(trans).collect(Collectors.toSet());
    }

    /**
     * 扁平化
     *
     * @param list list
     * @param flat flat
     * @param <T>  T
     * @param <V>  V
     * @return v 列表
     */
    public static <T, V> List<V> flat(Collection<T> list, Function<T, List<V>> flat) {
        List<V> v = new ArrayList<>();
        list.forEach(l -> v.addAll(flat.apply(l)));
        return v;
    }

    /**
     * 转换数组
     *
     * @param list      list
     * @param trans     trans
     * @param generator generator
     * @param <T>       T
     * @param <V>       V
     * @return V 数组
     */
    public static <T, V> V[] transArray(Collection<T> list, Function<T, V> trans, IntFunction<V[]> generator) {
        return list.stream().map(trans).toArray(generator);
    }

    /**
     * 过滤
     *
     * @param list   list
     * @param filter filter
     * @param <T>    T
     * @return List
     */
    public static <T> List<T> filter(Collection<T> list, Predicate<T> filter) {
        return list.stream().filter(filter).collect(Collectors.toList());
    }

    /**
     * 有序分组
     *
     * @param classifier Collectors.groupingBy#classifier
     * @param downstream Collectors.groupingBy#downstream
     * @param <T>        T
     * @param <K>        K
     * @param <A>        A
     * @param <D>        D
     * @return Collector
     */
    public static <T, K, A, D> Collector<T, ?, Map<K, D>> orderlyGroupBy(Function<? super T, ? extends K> classifier, Collector<? super T, A, D> downstream) {
        return Collectors.groupingBy(classifier, LinkedHashMap::new, downstream);
    }

    /**
     * 有序组合
     *
     * @param keyMapper   Collectors.toMap#keyMapper
     * @param valueMapper Collectors.toMap#valueMapper
     * @param <T>         T
     * @param <K>         K
     * @param <U>         U
     * @return Collector
     */
    public static <T, K, U> Collector<T, ?, Map<K, U>> orderlyToMap(Function<? super T, ? extends K> keyMapper, Function<? super T, ? extends U> valueMapper) {
        return Collectors.toMap(keyMapper, valueMapper, (o, n) -> o, LinkedHashMap::new);
    }

    /**
     * 列表转Map
     *
     * @param list 列表
     * @param getK key方法
     * @param <T>  T
     * @param <K>  key
     * @return Map
     */
    public static <T, K> Map<K, T> toMap(Collection<T> list, Function<T, K> getK) {
        return list.stream().collect(Collectors.toMap(getK, e -> e));
    }

    /**
     * 列表转Map
     *
     * @param list 列表
     * @param getK key方法
     * @param <T>  T
     * @param <K>  key
     * @return Map
     */
    public static <T, K> Map<K, T> toMap(Collection<T> list, Function<T, K> getK, Predicate<? super T> filter) {
        return list.stream().filter(filter).collect(Collectors.toMap(getK, e -> e));
    }

    /**
     * 列表转Map
     *
     * @param list 列表
     * @param getK key方法
     * @param <T>  T
     * @param <K>  key
     * @return Map
     */
    public static <T, K, U> Map<K, U> toMap(Collection<T> list, Function<T, K> getK, Function<? super T, ? extends U> getV, Predicate<? super T> filter) {
        return list.stream().filter(filter).collect(Collectors.toMap(getK, getV));
    }

    /**
     * 列表转Map
     *
     * @param list 列表
     * @param getK key方法
     * @param <T>  T
     * @param <K>  key
     * @return Map
     */
    public static <T, K, U> Map<K, U> toMap(Collection<T> list, Function<T, K> getK, Function<? super T, ? extends U> getV) {
        return list.stream().collect(Collectors.toMap(getK, getV, (k1, k2) -> k1));
    }

    /**
     * 列表转二维Map
     *
     * @param list 列表
     * @param getK 第一维 key
     * @param getV 第一维 value（列表）
     * @param getA 第二维 key
     * @param <T>  T
     * @param <K>  K
     * @param <V>  V
     * @param <A>  A
     * @return 二维Map
     */
    public static <T, K, V, A> Map<K, Map<A, V>> toMapAndThen(Collection<T> list, Function<T, K> getK, Function<? super T, Collection<V>> getV, Function<V, A> getA) {
        return list.stream().collect(Collectors.toMap(getK, e -> getV.apply(e).stream().collect(Collectors.toMap(getA, v -> v))));
    }

    /**
     * 列表转二维Map
     *
     * @param list 列表
     * @param getK 第一维 key
     * @param getV 第一维 value（列表）
     * @param getA 第二维 key
     * @param <T>  T
     * @param <K>  K
     * @param <V>  V
     * @param <A>  A
     * @return 二维Map
     */
    public static <T, K, V, A, B> Map<K, Map<A, B>> toMapAndThen(Collection<T> list, Function<T, K> getK, Function<? super T, Collection<V>> getV, Function<V, A> getA, Function<V, B> getB) {
        return list.stream().collect(Collectors.toMap(getK, e -> getV.apply(e).stream().collect(Collectors.toMap(getA, getB))));
    }

    /**
     * 列表转有序Map
     *
     * @param list 列表
     * @param getK key方法
     * @param <T>  T
     * @param <K>  key
     * @return Map
     */
    public static <T, K> Map<K, T> toOrderlyMap(Collection<T> list, Function<T, K> getK) {
        return list.stream().collect(CommonStreamUtil.orderlyToMap(getK, e -> e));
    }

    /**
     * 列表转有序Map
     *
     * @param list 列表
     * @param getK key方法
     * @param <T>  T
     * @param <K>  key
     * @return Map
     */
    public static <T, K> Map<K, T> toOrderlyMap(Collection<T> list, Function<T, K> getK, Comparator<T> comparator) {
        return list.stream().sorted(comparator).collect(CommonStreamUtil.orderlyToMap(getK, e -> e));
    }

    /**
     * 列表转有序Map
     *
     * @param list 列表
     * @param getK key方法
     * @param <T>  T
     * @param <K>  key
     * @return Map
     */
    public static <T, K, U> Map<K, U> toOrderlyMap(Collection<T> list, Function<T, K> getK, Function<? super T, ? extends U> getV) {
        return list.stream().collect(CommonStreamUtil.orderlyToMap(getK, getV));
    }

    /**
     * 列表转有序Map
     *
     * @param list 列表
     * @param getK key方法
     * @param <T>  T
     * @param <K>  key
     * @return Map
     */
    public static <T, K> Map<K, T> toOrderlyMap(Collection<T> list, Function<T, K> getK, Predicate<T> filter) {
        return list.stream().filter(filter).collect(CommonStreamUtil.orderlyToMap(getK, e -> e));
    }

    /**
     * 列表转有序Map
     *
     * @param list 列表
     * @param getK key方法
     * @param <T>  T
     * @param <K>  key
     * @return Map
     */
    public static <T, K, V> Map<K, V> toOrderlyMap(Collection<T> list, Function<T, K> getK, Function<T, V> getV, Predicate<T> filter) {
        return list.stream().filter(filter).collect(CommonStreamUtil.orderlyToMap(getK, getV));
    }

    /**
     * 转换Map
     *
     * @param map  map
     * @param getK key方法
     * @param <K>  K
     * @param <U>  U
     * @param <A>  A
     * @return Map
     */
    public static <K, U, A> Map<A, U> transMap(Map<K, U> map, Function<K, A> getK) {
        return map.entrySet().stream().collect(Collectors.toMap(e -> getK.apply(e.getKey()), Map.Entry::getValue));
    }

    /**
     * 转换Map
     *
     * @param map    map
     * @param getK   key方法
     * @param filter 过滤
     * @param <K>    K
     * @param <U>    U
     * @param <A>    A
     * @return Map
     */
    public static <K, U, A> Map<A, U> transMap(Map<K, U> map, Function<K, A> getK, BiPredicate<K, U> filter) {
        return map.entrySet().stream().filter(entry -> filter.test(entry.getKey(), entry.getValue()))
                .collect(Collectors.toMap(e -> getK.apply(e.getKey()), Map.Entry::getValue));
    }

    /**
     * 转换Map
     *
     * @param map  map
     * @param getK key方法
     * @param getV VALUE方法
     * @param <K>  K
     * @param <U>  U
     * @param <A>  A
     * @param <D>  D
     * @return Map
     */
    public static <K, U, A, D> Map<A, D> transMap(Map<K, U> map, Function<K, A> getK, Function<U, D> getV) {
        return map.entrySet().stream().collect(Collectors.toMap(e -> getK.apply(e.getKey()), e -> getV.apply(e.getValue())));
    }

    /**
     * 转换Map
     *
     * @param map  map
     * @param getK key方法
     * @param getV VALUE方法
     * @param <K>  K
     * @param <U>  U
     * @param <A>  A
     * @param <D>  D
     * @return Map
     */
    public static <K, U, A, D> Map<A, D> transMap(Map<K, U> map, Function<K, A> getK, BiFunction<K, U, D> getV) {
        return map.entrySet().stream().collect(Collectors.toMap(e -> getK.apply(e.getKey()), e -> getV.apply(e.getKey(), e.getValue())));
    }

    /**
     * 转换Map
     *
     * @param map  map
     * @param getV VALUE方法
     * @param <K>  K
     * @param <U>  U
     * @param <D>  D
     * @return Map
     */
    public static <K, U, D> Map<K, D> transMapValue(Map<K, U> map, Function<U, D> getV) {
        return map.entrySet().stream().collect(Collectors.toMap(Map.Entry::getKey, e -> getV.apply(e.getValue())));
    }

    /**
     * 转换Map
     *
     * @param map   map
     * @param trans trans
     * @param <K>   K
     * @param <U>   U
     * @param <T>   Y
     * @return List
     */
    public static <K, U, T> List<T> transMapList(Map<K, U> map, BiFunction<K, U, T> trans) {
        return map.entrySet().stream().map(e -> trans.apply(e.getKey(), e.getValue())).collect(Collectors.toList());
    }

    /**
     * 转换Map
     *
     * @param map   map
     * @param trans trans
     * @param <K>   K
     * @param <U>   U
     * @param <T>   Y
     * @return List
     */
    public static <K, U, T> List<T> transMapList(Map<K, U> map, BiPredicate<K, U> filter, BiFunction<K, U, T> trans) {
        return map.entrySet().stream().filter(e -> filter.test(e.getKey(), e.getValue())).map(e -> trans.apply(e.getKey(), e.getValue())).collect(Collectors.toList());
    }

    /**
     * 转换Map
     *
     * @param map  map
     * @param getV VALUE方法
     * @param <K>  K
     * @param <U>  U
     * @param <D>  D
     * @return Map
     */
    public static <K, U, D> Map<K, D> transMapValue(Map<K, U> map, BiFunction<K, U, D> getV) {
        return map.entrySet().stream().collect(Collectors.toMap(Map.Entry::getKey, e -> getV.apply(e.getKey(), e.getValue())));
    }

    /**
     * 拼接 value为List的Map 的values
     *
     * @param map map
     * @param <K> k
     * @param <U> u
     * @return Collection
     */
    public static <K, U, L extends Collection<U>> L concatMapColValues(Map<K, L> map, Supplier<L> get) {
        L l = null;
        for (L value : map.values()) {
            if (Objects.isNull(l)) {
                l = get.get();
            }
            l.addAll(value);
        }
        return l;
    }

    /**
     * 拼接 value为List的Map 的values
     *
     * @param map map
     * @param <K> k
     * @param <U> u
     * @return Collection
     */
    public static <K, U, L extends Collection<U>> L concatMapColValues(Map<K, L> map, Predicate<K> filter, L l) {
        map.forEach((k, v) -> {
            if (filter.test(k)) {
                l.addAll(v);
            }
        });
        return l;
    }

    /**
     * 拼接对象列表中 数组属性
     *
     * @param list list
     * @param getL getL
     * @param <T>  T
     * @param <L>  L
     * @return List
     */
    public static <T, L> List<L> concatList(Collection<T> list, Function<T, List<L>> getL) {
        List<L> l = new ArrayList<>();
        list.forEach(e -> l.addAll(getL.apply(e)));
        return l;
    }

    /**
     * 拼接values
     *
     * @param map map
     * @param <K> k
     * @param <A> a
     * @param <B> b
     * @return Map
     */
    public static <K, A, B> Map<A, B> concatMapValues(Map<K, Map<A, B>> map) {
        Map<A, B> result = new LinkedHashMap<>();
        map.values().forEach(result::putAll);
        return result;
    }

    /**
     * 拼接map key和values 为新的set
     *
     * @param map map
     * @param <T> t
     * @return Collection
     */
    public static <T> Set<T> concatMapKeyValues(Map<T, T> map) {
        return CollUtil.unionDistinct(map.keySet(), map.values());
    }

    /**
     * 拼接map 转换后的values
     *
     * @param map   map
     * @param trans trans
     * @param <K>   K
     * @param <U>   U
     * @param <L>   L
     * @param <T>   T
     * @return Set
     */
    public static <K, U, L extends Collection<U>, T> Set<T> concatMapTransValues(Map<K, L> map, Function<U, T> trans, Supplier<L> get) {
        L us = CommonStreamUtil.concatMapColValues(map, get);
        return Objects.nonNull(us) ? CommonStreamUtil.transSet(us, trans) : new HashSet<>();
    }

    /**
     * 分组
     *
     * @param list list
     * @param getK key方法
     * @param <T>  T
     * @param <K>  K
     * @return Map
     */
    public static <T, K> Map<K, List<T>> group(Collection<T> list, Function<T, K> getK) {
        return list.stream().collect(Collectors.groupingBy(getK));
    }

    /**
     * 分组
     *
     * @param list list
     * @param getK key方法
     * @param <T>  T
     * @param <K>  K
     * @return Map
     */
    public static <T, K> Map<K, List<T>> groupingBy(Collection<T> list, Comparator<T> comparator, Function<T, K> getK) {
        return list.stream().sorted(comparator).collect(Collectors.groupingBy(getK, LinkedHashMap::new, Collectors.toList()));
    }

    /**
     * 分组
     *
     * @param list list
     * @param getK key方法
     * @param <T>  T
     * @param <K>  K
     * @return Map
     */
    public static <T, K, V> Map<K, List<V>> groupAndThen(Collection<T> list, Function<T, K> getK, Function<List<T>, List<V>> getV) {
        return list.stream().collect(Collectors.groupingBy(getK, Collectors.collectingAndThen(Collectors.toList(), getV)));
    }

    /**
     * 分组
     *
     * @param list list
     * @param getK key方法
     * @param <T>  T
     * @param <K>  K
     * @return Map
     */
    public static <T, K, V> Map<K, List<V>> groupAndThenList(Collection<T> list, Function<T, K> getK, Function<T, V> getV) {
        return list.stream().collect(Collectors.groupingBy(getK, Collectors.collectingAndThen(Collectors.toList(),
                child -> child.stream().map(getV).collect(Collectors.toList()))));
    }

    /**
     * 分组
     *
     * @param list list
     * @param getK key方法
     * @param <T>  T
     * @param <K>  K
     * @return Map
     */
    public static <T, K, A, B> Map<K, Map<A, B>> groupAndThenMap(Collection<T> list, Function<T, K> getK, Function<List<T>, Map<A, B>> toMap) {
        return list.stream().collect(Collectors.groupingBy(getK, Collectors.collectingAndThen(Collectors.toList(), toMap)));
    }

    /**
     * 分组
     *
     * @param list list
     * @param getK key方法
     * @param <T>  T
     * @param <K>  K
     * @return Map
     */
    public static <T, K, A> Map<K, Map<A, List<T>>> groupAndThenGroup(Collection<T> list, Function<T, K> getK, Function<T, A> getV) {
        return list.stream().collect(Collectors.groupingBy(getK, Collectors.collectingAndThen(Collectors.toList(), l -> CommonStreamUtil.group(l, getV))));
    }

    /**
     * 分组 (排序)
     *
     * @param list list
     * @param getK key方法
     * @param <T>  T
     * @param <K>  K
     * @return Map
     */
    public static <T, K, U extends Comparable<? super U>> Map<K, List<T>> groupAndThenSorted(Collection<T> list, Function<T, K> getK, Comparator<? super T> comparator) {
        return list.stream().sorted(comparator).collect(CommonStreamUtil.orderlyGroupBy(getK, Collectors.toList()));
    }

    /**
     * 任意符合
     *
     * @param list      list
     * @param predicate 判断方法
     * @param <T>       T
     * @return Map
     */
    public static <T> boolean anyMatch(Collection<T> list, Predicate<? super T> predicate) {
        return list.stream().anyMatch(predicate);
    }

    /**
     * 从map中获取值
     *
     * @param map  map
     * @param keys keys
     * @param <K>  K
     * @param <V>  V
     * @return List
     */
    public static <K, V> List<V> findMapValue(Map<K, V> map, List<K> keys) {
        return keys.stream().filter(map::containsKey).map(map::get).collect(Collectors.toList());
    }
}
